[アップデート] VPC のサブネットルートテーブルでローカルルートより具体的なルートを指定できるようになりました!
コンバンハ、千葉(幸)です。
VPC 内部のサブネット間の通信において、アプライアンスなどを経由させる構成が取りやすくなりました。
サブネットルートテーブルと言えばデフォルトで以下のルートを持ち、それより具体的な( VPC CIDR 範囲より小さい)ルートは追加できない、というのがこれまでの常識でした。ガラッとその前提が変わることになりました。
送信先 | ターゲット |
---|---|
VPC 全体の CIDR 範囲 | local |
今回のアップデートで可能になった「より具体的なルート」を使用する機会は、アプライアンス製品を使用する場合など、少し特殊なケースに限定されるかと思います。とは言え、新たにできるようになったことは覚えておきましょう。
北-南のトラフィックと東-西のトラフィック
今回のアップデートを取り上げる上で切り離せないのは VPC Ingress Routing の話題です。
これはインターネットゲートウェイ(IGW)や仮想プライベートゲートウェイ(VGW)を経由して VPC 内に入ってくるトラフィックをルーティングできる機能で、2019年12月に発表されました。
当時の発表ブログ から画像引用すると、以下のイメージです。
クライアントから見た宛先は最下段のアプリケーションインスタンスですが、IGW を経由して VPC 内に入ってきた際にアプライアンスインスタンスへルーティングさせています。これは IGW にアタッチされたルートテーブル(ゲートウェイルートテーブル)の働きによるものです。この機能の発表と共に、IGW、VGWにルートテーブルをアタッチできるようになりました。
(これ以降、一般的な呼称か分かりませんが、アタッチする対象にあわせて「ゲートウェイルートテーブル」「サブネットルートテーブル」と呼び分けるようにわたしはしています。)
こういった VPC 外部からのインバウンド通信を、冒頭のブログでは North-south traffic と紹介しています。これは AWS 特有の表現ではなく、とある構成下におけるネットワークの通信方向を表す一般的なものです。北から南へのトラフィックは、外部のユーザーからデータセンター内部(今回では VPC が相当)への方向を表すようです。初めて知りましたがお洒落ですね。
それに対して East-west traffic はデータセンター内部の通信を表します。 VPC に置き換えて考えると、同一 VPC 内のサブネット間での通信が該当します。
East-west traffic におけるアプライアンスへのルーティングのイメージを今回のブログ から画像引用すると、以下となります。
最終的な宛先はアプリケーションインスタンスであるものの途中でアプライアンスインスタンスを経由させている、というのは北-南の場合と変わらないですね。
VPC Ingress Routing の場合はゲートウェイルートテーブルの働きにより実現されていましたが、今回はサブネットルートテーブル上のエントリにより実現されています。
この例での VPC の CIDR は10.0.0.0/16
ですが、それより具体的な10.0.0.0/24
や10.0.1.0/24
を宛先とするルートが追加されています。従来はこれを登録しようとするとエラー *1が発生していましたので、今回のアップデートによりその制約を受けなくなった、という考え方となります。
ミドルボックスアプライアンスのルーティングについての補足
ここまで見てきたような北-南、東-西のトラフィックをルーティングする構成については、以下ドキュメントで「ミドルボックスアプライアンスのルーティング」として取り上げられています。
イメージ図もより簡略化されて表現されていますので、あわせてご参照ください。
ゲートウェイとアプライアンス間のトラフィックのルーティング。
サブネット間トラフィックのアプライアンスへのルーティング。
詳細な考慮事項は上記をご確認いただくとして、「より具体的なルート」でターゲットとして指定できるものとして以下のコンポーネントが挙げられています。
- ゲートウェイロードバランサーエンドポイント
- NAT ゲートウェイ
- ネットワークファイアウォールエンドポイント
- ネットワークインタフェース(ENI)
アプライアンスインスタンスの ENI をターゲットにする、というのは分かりやすいですが、他のコンポーネントを使うときはどういった形になるのでしょうか……。何か面白い使用例が出てくることに期待です。
やってみた
ブログの構成をほぼほぼ踏襲し、以下のような構成で踏み台からアプリケーションインスタンスへの通信を行います。
踏み台→アプリケーションインスタンスへの通信をアプライアンスインスタンス上で tcpdump で確認できることろをゴールとします。
ご丁寧にサンプルの構成の CDK スクリプトを用意してくれているのですが、今回はマネジメントコンソールから頑張ってポチポチして作りました。
ざっくり以下の条件を満たす構成にしているところから始めます。
- VPC 一式作成済み
- サブネットの CIDR はサンプルと同一
- サブネットはすべてパブリックサブネット
- (サンプルでは踏み台のみパブリックですが、サブネット間ルーティングの確認には影響ないので、、)
- EC2 インスタンス構築済み
- すべて Amazon Linux2
- デフォルト状態
- SecuriryGroup は同一のものを使用し、相互参照許可あり
- 自身と同一の SecuriryGroup を持つものとイン/アウトすべて許可
サブネットルートテーブルの編集
たとえば踏み台サブネットに関連づけるルートテーブルであれば、以下のようにアプリケーションサブネットを指定したルートを追加しています。
編集時のイメージは以下です。ENI に付与した Name タグをあわせて表示してくれるので、どのインスタンスの ENI か迷わず選択することができました。今回はもちろんアプライアンスインスタンスのものを選んでいます。
同様のルートの編集を、アプリケーションサブネットに関連づくルートテーブルでも行っています。
アプライアンスインスタンスの設定
2点設定を行います。
まずはインスタンスの設定で、ソース/宛先チェックを無効化します。
これで自身が宛先でないトラフィックを受け入れられるようになりました。
続いて IP フォワードの設定です。セッションマネージャーで接続後、設定を行いました。
sh-4.2$ uname -a Linux ip-10-0-2-167.ap-northeast-3.compute.internal 4.14.238-182.422.amzn2.x86_64 #1 SMP Tue Jul 20 20:35:54 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux sh-4.2$ sudo sysctl -w net.ipv4.ip_forward=1 net.ipv4.ip_forward = 1
(uname -a
はホスト名の中に含まれる IP アドレスを確認する意図で叩いています。以降も出てきますが、そこまで気にしないでいただいて大丈夫です。)
アプリケーションインスタンスの設定
今回は httpd をインストールして起動させます。こちらもセッションマネージャーで接続後、作業を行いました。
sh-4.2$ uname -a Linux ip-10-0-1-34.ap-northeast-3.compute.internal 4.14.238-182.422.amzn2.x86_64 #1 SMP Tue Jul 20 20:35:54 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux sh-4.2$ sudo yum install httpd # 実行ログは省略 sh-4.2$ sudo systemctl start httpd sh-4.2$ sudo systemctl status httpd ● httpd.service - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled) Active: active (running) since Tue 2021-08-31 12:28:20 UTC; 4s ago Docs: man:httpd.service(8) Main PID: 2567 (httpd) Status: "Processing requests..." CGroup: /system.slice/httpd.service ├─2567 /usr/sbin/httpd -DFOREGROUND ├─2571 /usr/sbin/httpd -DFOREGROUND ├─2573 /usr/sbin/httpd -DFOREGROUND ├─2578 /usr/sbin/httpd -DFOREGROUND ├─2580 /usr/sbin/httpd -DFOREGROUND └─2585 /usr/sbin/httpd -DFOREGROUND Aug 31 12:28:20 ip-10-0-1-34.ap-northeast-3.compute.internal systemd[1]: Starting The Apache HTTP Server... Aug 31 12:28:20 ip-10-0-1-34.ap-northeast-3.compute.internal systemd[1]: Started The Apache HTTP Server.
中身は空ですがドキュメントルートにindex.html
を作っておきます。(デフォルトだとステータスコードが 403 になってなんとなく収まりが悪いため。)
sh-4.2$ sudo touch /var/www/html/index.html sh-4.2$ ls -la /var/www/html/ total 0 drwxr-xr-x 2 root root 24 Aug 31 12:53 . drwxr-xr-x 4 root root 33 Aug 31 12:27 .. -rw-r--r-- 1 root root 0 Aug 31 12:53 index.html
踏み台インスタンスからのアクセス
踏み台インスタンスに接続後、アプリケーションインスタンスに向けて接続を行います。
sh-4.2$ uname -a Linux ip-10-0-0-146.ap-northeast-3.compute.internal 4.14.238-182.422.amzn2.x86_64 #1 SMP Tue Jul 20 20:35:54 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux sh-4.2$ curl -I -v 10.0.1.34 * Rebuilt URL to: 10.0.1.34/ * Trying 10.0.1.34... * TCP_NODELAY set * Connected to 10.0.1.34 (10.0.1.34) port 80 (#0) > HEAD / HTTP/1.1 > Host: 10.0.1.34 > User-Agent: curl/7.61.1 > Accept: */* > < HTTP/1.1 200 OK HTTP/1.1 200 OK < Date: Tue, 31 Aug 2021 12:56:26 GMT Date: Tue, 31 Aug 2021 12:56:26 GMT < Server: Apache/2.4.48 () Server: Apache/2.4.48 () < Upgrade: h2,h2c Upgrade: h2,h2c < Connection: Upgrade Connection: Upgrade < Last-Modified: Tue, 31 Aug 2021 12:53:54 GMT Last-Modified: Tue, 31 Aug 2021 12:53:54 GMT < ETag: "0-5cada71337a9a" ETag: "0-5cada71337a9a" < Accept-Ranges: bytes Accept-Ranges: bytes < Content-Type: text/html; charset=UTF-8 Content-Type: text/html; charset=UTF-8 < * Connection #0 to host 10.0.1.34 left intact
ひとまずここではステータスコード 200 が返ってきたことが確認できます。
アプライアンスインスタンスでの tcpdump
順番は前後するのですが、上記の操作を行う前にアプライアンスインスタンスで tcpdump を実行しています。
sh-4.2$ uname -a Linux ip-10-0-2-167.ap-northeast-3.compute.internal 4.14.238-182.422.amzn2.x86_64 #1 SMP Tue Jul 20 20:35:54 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux sh-4.2$ sudo tcpdump -i eth0 host 10.0.0.146 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
↑host で指定しているのは踏み台インスタンスの IP アドレスです。
このリッスン状態で踏み台インスタンスから curl を行うと、以下のように通信の内容が確認できます。
12:56:26.976133 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [S], seq 1643808848, win 26883, options [mss 8961,sackOK,TS val 1240133501 ecr 0,nop,wscale 7], length 0 12:56:26.976151 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [S], seq 1643808848, win 26883, options [mss 8961,sackOK,TS val 1240133501 ecr 0,nop,wscale 7], length 0 12:56:26.976324 IP 10.0.1.34.http > 10.0.0.146.44714: Flags [S.], seq 2834299818, ack 1643808849, win 26847, options [mss 8961,sackOK,TS val 2462081390 ecr 1240133501,nop,wscale 6], length 0 12:56:26.976334 IP 10.0.1.34.http > 10.0.0.146.44714: Flags [S.], seq 2834299818, ack 1643808849, win 26847, options [mss 8961,sackOK,TS val 2462081390 ecr 1240133501,nop,wscale 6], length 0 12:56:26.976407 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [.], ack 1, win 211, options [nop,nop,TS val 1240133501 ecr 2462081390], length 0 12:56:26.976411 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [.], ack 1, win 211, options [nop,nop,TS val 1240133501 ecr 2462081390], length 0 12:56:26.976437 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [P.], seq 1:75, ack 1, win 211, options [nop,nop,TS val 1240133501 ecr 2462081390], length 74: HTTP: HEAD / HTTP/1.1 12:56:26.976439 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [P.], seq 1:75, ack 1, win 211, options [nop,nop,TS val 1240133501 ecr 2462081390], length 74: HTTP: HEAD / HTTP/1.1 12:56:26.976505 IP 10.0.1.34.http > 10.0.0.146.44714: Flags [.], ack 75, win 420, options [nop,nop,TS val 2462081391 ecr 1240133501], length 0 12:56:26.976507 IP 10.0.1.34.http > 10.0.0.146.44714: Flags [.], ack 75, win 420, options [nop,nop,TS val 2462081391 ecr 1240133501], length 0 12:56:26.976698 IP 10.0.1.34.http > 10.0.0.146.44714: Flags [P.], seq 1:254, ack 75, win 420, options [nop,nop,TS val 2462081391 ecr 1240133501], length 253: HTTP: HTTP/1.1 200 OK 12:56:26.976701 IP 10.0.1.34.http > 10.0.0.146.44714: Flags [P.], seq 1:254, ack 75, win 420, options [nop,nop,TS val 2462081391 ecr 1240133501], length 253: HTTP: HTTP/1.1 200 OK 12:56:26.976761 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [.], ack 254, win 219, options [nop,nop,TS val 1240133501 ecr 2462081391], length 0 12:56:26.976763 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [.], ack 254, win 219, options [nop,nop,TS val 1240133501 ecr 2462081391], length 0 12:56:26.976975 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [F.], seq 75, ack 254, win 219, options [nop,nop,TS val 1240133502 ecr 2462081391], length 0 12:56:26.976977 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [F.], seq 75, ack 254, win 219, options [nop,nop,TS val 1240133502 ecr 2462081391], length 0 12:56:26.977046 IP 10.0.1.34.http > 10.0.0.146.44714: Flags [F.], seq 254, ack 76, win 420, options [nop,nop,TS val 2462081391 ecr 1240133502], length 0 12:56:26.977048 IP 10.0.1.34.http > 10.0.0.146.44714: Flags [F.], seq 254, ack 76, win 420, options [nop,nop,TS val 2462081391 ecr 1240133502], length 0 12:56:26.977097 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [.], ack 255, win 219, options [nop,nop,TS val 1240133502 ecr 2462081391], length 0 12:56:26.977099 IP 10.0.0.146.44714 > 10.0.1.34.http: Flags [.], ack 255, win 219, options [nop,nop,TS val 1240133502 ecr 2462081391], length 0
踏み台インスタンスとアプリケーションインスタンスの双方向で通信を行っている様が見て取れますね。
サブネット間のトラフィックをアプライアンスにルーティングできていることが確認できました!
ちなみに:サブネットルートテーブルの仕様
VPC 全体の CIDR を宛先とするルートが削除できないのは従来と変わりませんが、ターゲットはローカルである必要はなくなりました。
この場合、対象のサブネットに配置されたリソースから VPC 内部宛のトラフィックはすべて、ターゲットに指定されたコンポーネントを向くことになります。
この状態で10.0.0.0/16
からたとえば10.0.0.0/24
のようなより具体的なルートに変更すると、エラーが発生します。
cannot remove local route 10.0.0.0/16 in route table rtb-0xxxxxxxxxxxxx
たとえターゲットが「ローカル」でなくても、 VPC の CIDR 範囲全体を宛先とするルートは必要ということですね。
なるほど。覚えておきましょう。
終わりに
サブネットルートテーブルでローカルルートより具体的なルートを指定できるようになった、というアップデートでした。
VPC Ingress Routing の発表後、VPC 内のサブネット間の通信でもアプライアンスを経由させる構成をとりたい、という要望があったために追加された機能とのことです。
正直わたしはそのような製品を扱う環境に携わったことがないのでどのくらい要望があるのか見えていないのですが、いざという時に間違えないよう、「できること」を押さえておくのは重要かなと思います。
ターゲットの「ローカル」が固定でなくなった、というのはもろもろ影響ありそうですので、改めて仕様を覚えなおしておきましょう。
以上、 チバユキ (@batchicchi) がお送りしました。
参考
- VPC Ingress Routingとは何かを噛み砕いて理解してみる | DevelopersIO
- [VPC Ingress Routing]IGWとVGWにルートテーブルをアタッチ!全ての通信をEC2経由へ。サードパーティIDS製品などの通信をシンプルに #reinvent | DevelopersIO
脚注
- This route table is used by a subnet, and doesn't support route destination which are more specific than VPC local CIDR.といったエラーが発生していました。 ↩